#!/bin/bash

# FABRIC_SRC_PATH="$GOPATH/src/github.com/hyperledger/"
FABRIC_SDK_PATH="$GOPATH/src/github.com/hyperledger/fabric-sdk"
FABRIC_SDK_BRANCH=
FABRIC_CHANNEL="mychannel"
FABRIC_CHAINCODE_NAME="mycc"

source /etc/profile
source cluster_IP.conf

usage="usage: $0 -b/--branch <branch>\n"
usage=$usage"\t-b, --branch: fabric sdk branch which deploy\n"

usage_exit() {
    printf "$usage"
    exit
}

function wait_sometime() {
    for((i=1; i<=$1; i++))
    do
        sleep 1s
        echo "wait ${i}s ..."
    done
}

function clone_fabric_sdk() {
    echo -n "clone fabric-sdk to all nodes ... "
    for node in ${FABRIC_PEER_IP[@]}
    do
        ssh $node "
            source /etc/profile
            while [ ! -d "$FABRIC_SDK_PATH" ]; do
                git clone -q https://gitee.com/czy233/fabric-sdk.git $FABRIC_SDK_PATH
                sleep 10s
            done
            cd $FABRIC_SDK_PATH
            git pull -q
            git checkout $FABRIC_SDK_BRANCH -q
        " &
    done
    wait
    for node in ${FABRIC_ORDERER_IP[@]}
    do
        ssh $node "
            source /etc/profile
            while [ ! -d "$FABRIC_SDK_PATH" ]; do
                git clone -q https://gitee.com/czy233/fabric-sdk.git $FABRIC_SDK_PATH
                sleep 10s
            done
            cd $FABRIC_SDK_PATH
            git pull -q
            git checkout $FABRIC_SDK_BRANCH -q
        " &
    done 
    wait
    echo "done"
}

function config_hosts_for_nodes() {
    echo -n "config hosts ... "
    for node in ${FABRIC_PEER_IP[@]}
    do
        ssh $node "cd $FABRIC_SDK_PATH; ./hosts_config.sh > /dev/null 2>&1" &
    done
    wait
    for node in ${FABRIC_ORDERER_IP[@]}
    do
        ssh $node "cd $FABRIC_SDK_PATH; ./hosts_config.sh > /dev/null 2>&1" &
    done
    wait
    echo "done"
}

function start_fabric_cluster() {
    echo "start fabric network"
    i=1
    for node in ${FABRIC_PEER_IP[@]}
    do
        ssh $node " export IMAGE_TAG='latest'
                    export COMPOSE_PROJECT_NAME='net'
                    source $FABRIC_SDK_PATH/fabric_ip.conf
                    cd $FABRIC_SDK_PATH/compose-up
                    docker-compose -f docker-compose-org${i}.yaml up -d
        " &
        let i=i+1
    done
    i=1
    for node in ${FABRIC_ORDERER_IP[@]}
    do
        ssh $node " export IMAGE_TAG='latest'
                    export COMPOSE_PROJECT_NAME='net'
                    source $FABRIC_SDK_PATH/fabric_ip.conf
                    cd $FABRIC_SDK_PATH/compose-up
                    docker-compose -f docker-compose-order${i}.yaml up -d
        " &
        let i=i+1
    done
    wait
    echo "finish start fabric network!"
}

function gen_join_channel() {
    # generate channel
    docker exec cli peer channel create -o orderer1.demo.com:7050 -c ${FABRIC_CHANNEL} -f ./channel-artifacts/channel.tx \
    --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/demo.com/orderers/orderer1.demo.com/msp/tlscacerts/tlsca.demo.com-cert.pem
    if [ $? -ne 0 ]; then
        echo "no Raft leader"
        return -1
    fi

    # join for cli/peer0.org1.demo.com
    docker exec cli peer channel join -b ${FABRIC_CHANNEL}.block
    docker exec cli peer channel update -o orderer1.demo.com:7050 -c ${FABRIC_CHANNEL} -f ./channel-artifacts/Org1MSPanchors.tx \
    --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/demo.com/orderers/orderer1.demo.com/msp/tlscacerts/tlsca.demo.com-cert.pem

    # copy to local host & cli1/peer1.org1.demo.com
    docker cp cli:/opt/gopath/src/github.com/hyperledger/fabric/peer/${FABRIC_CHANNEL}.block $FABRIC_SDK_PATH/compose-up/${FABRIC_CHANNEL}.block
    # docker cp $FABRIC_SDK_PATH/compose-up/${FABRIC_CHANNEL}.block cli1:/opt/gopath/src/github.com/hyperledger/fabric/peer/${FABRIC_CHANNEL}.block

    # join for cli1/peer1.org1.demo.com
    # docker exec cli1 peer channel join -b ${FABRIC_CHANNEL}.block

    # copy ${FABRIC_CHANNEL}.block to docker containers & join for cli{0..1}/peer{0..1}.org{2..4}.demo.com
    for ((i=1; i<${#FABRIC_PEER_IP[@]}; i++))
    do
        let j=i+1
        scp $FABRIC_SDK_PATH/compose-up/${FABRIC_CHANNEL}.block ${FABRIC_PEER_IP[$i]}:$FABRIC_SDK_PATH/compose-up/${FABRIC_CHANNEL}.block
        ssh ${FABRIC_PEER_IP[$i]} "
            docker cp $FABRIC_SDK_PATH/compose-up/${FABRIC_CHANNEL}.block cli:/opt/gopath/src/github.com/hyperledger/fabric/peer/${FABRIC_CHANNEL}.block
            docker exec cli peer channel join -b mychannel.block
            docker exec cli peer channel update -o orderer1.demo.com:7050 -c ${FABRIC_CHANNEL} -f ./channel-artifacts/Org${j}MSPanchors.tx --tls \
            --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/demo.com/orderers/orderer1.demo.com/msp/tlscacerts/tlsca.demo.com-cert.pem
        " &
    done
    wait
    return 0
}

function install_chaincode() {
    # copy chaincode to cli
    cd $FABRIC_SDK_PATH/chaincode/go/
    if [ ! -f "objhash_chaincode.go" ]; then
        echo "no chaincode exist, please put chaincode to $(pwd)"
        exit -1
    fi

    # install chaincode for org1
    docker exec cli peer chaincode install -n ${FABRIC_CHAINCODE_NAME} -p github.com/chaincode/go/ -v 1.0

    # instantiate chaincode
    # docker exec cli peer chaincode instantiate -o orderer1.demo.com:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/demo.com/orderers/orderer1.demo.com/msp/tlscacerts/tlsca.demo.com-cert.pem -C ${FABRIC_CHANNEL} -n ${FABRIC_CHAINCODE_NAME} -v 1.0 -c '{"Args":["init"]}' -P "OR ('Org1MSP.member', 'Org2MSP.member', 'Org3MSP.member', 'Org4MSP.member')"
    docker exec cli peer chaincode instantiate -o orderer1.demo.com:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/demo.com/orderers/orderer1.demo.com/msp/tlscacerts/tlsca.demo.com-cert.pem -C ${FABRIC_CHANNEL} -n ${FABRIC_CHAINCODE_NAME} -v 1.0 -c '{"Args":["init"]}' -P "OutOf(3, 'Org1MSP.member', 'Org2MSP.member', 'Org3MSP.member', 'Org4MSP.member')"

    # wait 5s for chaincode instantiate
    # wait_sometime 5

    # install chaincode for all peers
    for ((i=1; i<${#FABRIC_PEER_IP[@]}; i++))
    do
        ssh ${FABRIC_PEER_IP[$i]} "
            docker exec cli peer chaincode install -n ${FABRIC_CHAINCODE_NAME} -p github.com/chaincode/go/ -v 1.0
        " &
    done
    wait

    for ((i=1; i<${#FABRIC_PEER_IP[@]}; i++))
    do
        ssh ${FABRIC_PEER_IP[$i]} "
            docker exec cli peer chaincode invoke -o orderer1.demo.com:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/demo.com/orderers/orderer1.demo.com/msp/tlscacerts/tlsca.demo.com-cert.pem -C ${FABRIC_CHANNEL} -n ${FABRIC_CHAINCODE_NAME} -c '{\"Args\":[\"create\",\"obj_${i}\",\"123\"]}'
        " &
        let i=i+1
    done
    wait
    
    # docker exec cli peer chaincode invoke -o orderer1.demo.com:7050  --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/demo.com/orderers/orderer1.demo.com/msp/tlscacerts/tlsca.demo.com-cert.pem -C ${FABRIC_CHANNEL} -n ${FABRIC_CHAINCODE_NAME} -c '{"Args":["create","obj_0","123"]}'
    docker exec cli peer chaincode query -C ${FABRIC_CHANNEL} -n ${FABRIC_CHAINCODE_NAME} -c '{"Args":["read","object_0"]}'
}

if [ $# -ne 2 ]; then
    usage_exit
fi

while [ $# -ge 1 ]; do
case $1 in
    -b | --branch)
        [ -z "$2" ] && usage_exit
        FABRIC_SDK_BRANCH=$2
        shift
        ;;
    *)
        usage_exit
esac
shift
done

# GOPATH exist ?
if [ 0"$GOPATH" = "0" ]; then
    echo "GOPATH not exist, please install go and set it"
    exit -1
fi

# clone fabric-sdk from git
while [ ! -d "$FABRIC_SDK_PATH" ]; do
    git clone -q https://gitee.com/czy233/fabric-sdk.git $FABRIC_SDK_PATH
done
cd $FABRIC_SDK_PATH
git pull
git checkout $FABRIC_SDK_BRANCH

# crypto config files exist ?
cd $FABRIC_SDK_PATH/compose-up
if [[ ! -d "channel-artifacts" || ! -d "crypto-config" ]]; then
    echo "'crypto-config' & 'channel-artifacts' not exist"
    echo "please gen-crypto by hand && push it to fabric-sdk"
    exit -1
fi

# clone fabric-sdk to all nodes
clone_fabric_sdk

# config hosts in every node
config_hosts_for_nodes

# down & remove fabric containers may exist
cd $HOME/ceph_fabric_config/fabric_deploy_splitted_raft_1.4
./down_fabric_cluster.sh

# start fabric network
start_fabric_cluster

# wait or a few time wait raft leader election
wait_sometime 5

# generate & join channel for all peers
gen_join_channel
if [ $? -ne 0 ]; then
    echo "generate & join channel error"
    exit -1
fi

# install chaincode
install_chaincode
if [ $? -ne 0 ]; then
    echo "install chaincode error"
    exit -1
fi